package nodex

import (
	"context"
	"fmt"
	"gitee.com/zhongguo168a/go-nodex/nodex/server"
	"github.com/pkg/errors"
	"sync"
)

type MsgHandle struct {
	Server IServer
	//
	routers      map[string]*Router //存放每个MsgId 所对应的处理方法的map属性
	routersMutex sync.RWMutex
	// 上下文生成器
	contextCreator ContextCreator
	//
}

func NewMsgHandle(s server.IServer) *MsgHandle {
	return &MsgHandle{
		Server:  s,
		routers: make(map[string]*Router),
	}
}

//func SerializeDecode(mode SerializeMode, data []byte) (r interface{}, err error) {
//	switch mode {
//	case JSON:
//		err = json.Unmarshal(request.GetData(), args)
//		if err != nil {
//			err = errors.Wrap(err, "unmarshal json")
//			return
//		}
//	default:
//		err = errors.New("mode not found")
//	}
//	return
//}
//
func (mh *MsgHandle) GetRouters() (r map[string]server.IRouter) {
	mh.routersMutex.RLock()
	defer mh.routersMutex.RUnlock()

	r = map[string]server.IRouter{}
	for key, val := range mh.routers {
		r[key] = val
	}
	return
}

func (mh *MsgHandle) GetRoute(key string) server.IRouter {
	mh.routersMutex.RLock()
	defer mh.routersMutex.RUnlock()

	router, ok := mh.routers[key]
	if !ok {
		return nil
	}
	return router
}

func (mh *MsgHandle) GetContext(request *server.Request, router *Router) (lastctx IContext, err error) {
	ctx := &Context{
		conn:   request.Conn,
		requet: request,
		server: mh.Server,
	}
	ctx.Context = context.Background()
	switch router.Config.CallMode {
	case CHANRPC:
		rpcKey, serr := router.GetRPC(ctx, router)
		if serr != nil {
			err = errors.Wrap(serr, "get rpc")
			return
		}

		irpc := GetChanRPC(rpcKey)
		if irpc != nil {
			rpc := irpc.(IChanRPC)
			ctx.rpc = rpc
		}
	}
	//执行对应处理方法
	if router.GetContext != nil {
		lastctx, err = router.GetContext(ctx)
		if err != nil {
			err = errors.Wrap(err, "get context")
			return
		}
	} else {
		lastctx = ctx
	}

	return
}

//马上以非阻塞方式处理消息
func (mh *MsgHandle) Do(request *server.Request) (err error) {
	return
}

//为消息添加具体的处理逻辑
func (mh *MsgHandle) AddRouter(msgId string, irouter server.IRouter) {
	//1 判断当前msg绑定的API处理方法是否已经存在
	if _, ok := mh.routers[msgId]; ok {
		panic("repeated api , msgId = " + msgId)
	}
	router := irouter.(*Router)
	//2 添加msg与api的绑定关系
	mh.routers[msgId] = router

	if router.Config.CallMode == CHANRPC {
		selector, has := n.config.ChanRPCSelectors[router.Config.ChanRPC]
		if has == false {
			panic(errors.New(fmt.Sprintf("rpc selector not found [id=%v]", router.Config.ChanRPC)))
		}

		router.GetRPC = selector
	}

}
